Skip to content

Conversation

@Mingguriguri
Copy link
Collaborator

@Mingguriguri Mingguriguri commented May 17, 2025

🌱WIL

이번 한 주의 소감을 작성해주세요!

  • 발제&과제 문제는 "구현"과 관련한 문제였다. 구현 문제는 쉽게만 생각했는데 이번 문제들은 실버1이었음에도 굉장히 애를 먹었다. 조건도 제대로 설정해줘야 했고, 고려해야 할 사항이 많았다. 하지만 정말 중요한 건 문제의 내용을 제대로 파악하고 이해하는 것이었다. 발제&과제 문제 모두 문제를 대충 읽다가 문제 풀이 중반부에 잘못되었다는 것을 알게 되었다. 과제 문제의 경우 사각형 경계선을 1차원으로 단순화하는 발상이 인상깊었다. 이렇게 사고할 수도 있구나 알게 되었다.
  • 그 외의 문제들로는 Java로 코테 문제 풀이하는 것을 연습하기 위해 스택/큐 유형을 Java로 푸는 연습을 했다. 초반에는 파이썬에 익숙하다보니 같은 문제더라도 어떻게 구현해야 할 지 감이 아예 오지 않았다. 문제를 풀이하면서 import java.util.*; 를 해야 한다는 점, 타입을 매번 지정해줘야 한다는 점, 파이썬이랑 함수가 다르다는 점, Array와 ArrayList의 함수가 다르다는 점, ArrayList로 한 후 다시 Array로 형태를 바꾸는 코드를 꼭 추가해야 한다는 점, DTO를 활용한다는 점 등등 정말 기본적인 문법들을 문제를 풀이하면서 익히게 되었다.

🚀주간 목표 문제 수: 3개


백준 #2512. 예산: 이분탐색 / 실버2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. N(지방 수), 각 지방의 예산 요청 리스트(budgets) 입력
  2. 총 예산 M 입력
  3. 총 요청 합이 M 이하이면 최대 요청값 출력
  4. 그렇지 않으면 다음 수행:
    • 이분 탐색 범위: left = 0, right = max(요청)
    • 반복:
      • mid = (left + right) // 2
      • total = sum(min(b, mid) for b in budgets)
      • total ≤ M 이면 answer = mid, left 증가
      • total > M 이면 right 감소
  5. 최종 answer 출력

🚩제출한 코드

import sys

input = sys.stdin.readline

def main():
    N = int(input())  # 지방의 수
    budgets = sorted(map(int, input().split()))  # 각 지방의 예상요청
    M = int(input())  # 총 예산

    # 1. 모든 요청이 배정될 수 있는 경우, 요청 최대값이 정답
    if sum(budgets) <= M:
        return budgets[-1]

    # 2. 모든 요청이 배정될 수 없는 경우, 상한액 탐색
    left = 0
    right = budgets[-1]
    answer = 0

    while left <= right:
        mid = (left + right) // 2 # 상한액
        total = 0
        for b in budgets:
            total += min(b, mid)

        if total <= M:
            # 이 상한액으로 배정해도 총액이 허용 범위 이내 → C를 더 높여 볼 수 있음
            answer = mid
            left = mid + 1
        else:
            # 총액이 초과 → 상한액을 낮춰야 함
            right = mid - 1

    return answer


if __name__ == '__main__':
    print(main())

💡TIL

배운 점이 있다면 입력해주세요

  • 매개변수 탐색을 연습하기 위해 해당 문제를 풀이했다. 하지만 도저히 어떻게 풀이해야 할 지 감이 오지 않아 결국 힌트를 보게 되었다.
  • 매개변수 탐색은 마치 DP처럼 구해야 하는 답을 left/right/mid로 두어 설정한다는 점을 발견했다. 문제를 조금 더 단순화하면 단순하게 접근해낼 수 있겠다는 생각을 하게 되었다.

프로그래머스 #42577. 전화번호 목록: 문자열 / Level2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 배열을 먼저 정렬한다.
  2. 배열의 현재 위치(i)값과 그 다음 위치(i+1)값을 차례로 비교하면서, 다음 위치 값이 현재 위치 값의 앞부분에 해당 문자열이 포함되어있는지 확인한다.
  3. 포함되어있다면 false, 포함되어있지 않다면 true를 반환한다.

🚩제출한 코드

import java.util.*;

class Solution {
    public boolean solution(String[] phone_book) {
        
        Arrays.sort(phone_book); // 오름차순 정렬

        for (int i = 0; i < phone_book.length - 1; i++ ) {
		        // 만약 다음 값이 현재 값으로 시작한다면, false 반환
            if (phone_book[i+1].startsWith(phone_book[i])) {
                return false;
            }
        }
        return true;
    }
}

💡TIL

배운 점이 있다면 입력해주세요

  • 파이썬에 익숙하다보니까 자바로 어떻게 구현해야 할 지 감이 아예 안 왔다. 파이썬 방식으로 구현하려면 슬라이싱을 이용해서 부르트포스로 탐색을 하면 된다.
  • 하지만 자바의 경우 문자열을 처리하는 이 부분을 어떻게 처리해야 할 지 감이 안 왔다.
  • 결국 풀이를 보게 되었다. 풀이에서는 새로운 방식으로 접근하고 있었다. 파이썬에서 자바로 접근하니 문제 풀이의 새로운 접근 방식을 알게되어 좋았다. 또 자바에서 사용하는 문자열 관련 함수들의 사용법에 대해 공부할 수 있었다. 파이썬과는 차이가 있어 따로 정리해두었다.
  • Arrays.sort(), startsWith(), endsWith() 은 나중에 또 유용하게 써먹어야겠다.
  • 그리고 자바는 ArrayList, HashMap, Math 함수 등 쓰려면 다 import 해야 한다. 파이썬에서 편하게 쓰던 abs(), min(), max()도 Math패키지를 import 해야 쓸 수 있으니까 시작하기 전에 꼭 import java.util.*; 추가해놓기!

프로그래머스 #12909. 올바른 괄호: 스택큐 / Level2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력 문자열을 문자 리스트로 변환
  2. 괄호 짝 검사 로직 실행
    • ( → push
    • ) → 비어있으면 false, 아니면 pop
  3. 루프 종료 후 스택이 비어 있으면 true, 아니면 false

🚩제출한 코드

import java.util.*;

class Solution {
    boolean solution(String s) {
        // "(" 이면 stack에 push. ")"이면 stack에서 pop하기
        // stack의 길이가 0이면 true, stack의 길이가 1이상이면 false
        
        // Stack ArrayList 
        ArrayList<Integer> stack = new ArrayList<>();
        
        // 문자열을 ArrayList로 변환
        String[] stringParam = s.split(""); 
        ArrayList<String> list = new ArrayList<String>(Arrays.asList(stringParam));

        // Stack Push & Pop
        for (String str: stringParam){
            // System.out.println(str);
            if (str.equals("(")) {
                stack.add(0);
                // System.out.println("추가 완료");
            }
            else {
		            // 처음부터 ) 가 나올 경우 올바르지 않은 괄호
                if (stack.size() == 0){
                    return false;
                }
                else {
                    stack.remove(stack.size() - 1);
                }
            }
        }
        
        // 올바른 괄호가 아닐 경우
        if (stack.size() > 0) {
            return false;
        } 
        // 올바른 괄호가 아닌 경우
        return true;
    }
}

💡TIL

배운 점이 있다면 입력해주세요
처음엔 Python으로 풀던 방식 그대로 Java에 적용하려 했는데, 문자열 처리, List/Stack 처리 등에서 문법 차이가 헷갈려서 많이 막혔다. 하지만 이렇게 하나씩 하나씩 자바 문법에 익숙해져가는 연습을 해야겠다.

String을 List로 변환하려고 asList()함수를 썼는데 적절하지 않은 선택이었다. 예를 들어 “()()”의 경우 [(, ), (, )]로 저장되어야 하는데 [”()()”] 으로 저장되게 된다.

List<String> stringParam = new ArrayList<>();
        
        for (char c : s.toCharArray()) {
            stringParam.add(String.valueOf(c));
        }

또 자바에는 java.util.Stack 패키지가 있어서 여기서 제공해주는 스택 관련한 함수를 바로 써도 된다는 것을 알게 되었다. ArrayList가 헷갈렸는데 Stack으로 배열 만들고 push, pop, isEmpty 함수를 바로 쓰게 되어 훨씬 간편하게 코드를 짤 수 있을 것 같다.


프로그래머스 #42586. 기능개발: 스택큐 / Level2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 각 기능의 남은 일수를 구한다.

    남은일수 = ceil((100 - 현재진도) / 속도)

  2. 큐에 일수를 넣어가며 다음 기능의 배포 여부를 판단한다.

  3. 앞 기능보다 일수가 작거나 같으면 같은 날 배포 (카운트 증가).

  4. 더 크면 이전 배포를 끝내고 새로운 배포 시작.

🚩제출한 코드

import java.util.*;

class Solution {
    public int[] solution(int[] progresses, int[] speeds) {
        ArrayList<Integer> answer = new ArrayList<>();
        ArrayList<Integer> queue = new ArrayList<>();
        
        for (int i=0; i < progresses.length; i++){
            int days = (int) Math.ceil((100.0 - progresses[i]) / speeds[i]);
            if (queue.size() > 0 && days > queue.get(0)) {
                answer.add(queue.size());
                queue.clear();
                queue.add(days);
                
            }
            else {
                queue.add(days);
            }
        }
        answer.add(queue.size());
        
        // 배열로 변환
        int[] arr = answer.stream()
                  .mapToInt(Integer::intValue)
                  .toArray();

        return arr;
    }
}

💡TIL

배운 점이 있다면 입력해주세요

  • List → 배열로 변환하는 법에 대해 알게 되었다. 이 부분이 단순하지 않아서 여기저기 찾아봤지만 케이스마다 다른 것 같다.
  • 형변환하는 것을 잊지말자! return 하는 값의 자료형도 맞춰줘야 한다는 것을 잊지말자.
  • Queue 클래스 내에서 처리할 수 있는 함수들이 파이썬보다 훨씬 다양했다. 좀 익힌 후에 활용하는데 써먹어봐야겠다.

프로그래머스 #42587. 프로세스: 스택큐 / Level2

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. DTO 클래스 정의 (index + priority)
  2. 일반 큐 queue에 DTO 삽입
  3. 우선순위 큐 pq에 priority 삽입
  4. 큐에서 하나씩 꺼내서 pq.peek()과 비교
  5. 실행되면 count++
  6. 실행된 것이 location이면 반환

🚩제출한 코드

import java.util.*;

class Solution {
    public int solution(int[] priorities, int location) {
        // 1) 작업 큐: 인덱스(idx)와 우선순위(priority)를 함께 보관
        Queue<DTO> queue = new LinkedList<>();
        
        // 2) 우선순위 큐: 남아있는 작업 중 가장 높은 우선순위를 꺼내기 위함
        PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        
        for (int i = 0 ; i < priorities.length; i++) {
            queue.offer(new DTO(i, priorities[i]));
            pq.offer(priorities[i]);
        }

        // System.out.println(queue);
        // System.out.println(pq);
        
        int count = 0; // 실행된 작업 수
        
        while(!queue.isEmpty()) {
            DTO cur = queue.poll(); // 현재 작업 꺼냄
            
            // 현재 작업 우선순위가 남은 작업의 최고 우선순위와 같다면
            if(cur.priority == pq.peek()) {
                count++;
                pq.poll(); // 우선순위 큐에서 제거
                // 내가 찾던 작업이라면 실행 순서 반환
                if (cur.idx == location) {
                    return count;
                }
            }
            else {
		            // 우선순위가 더 높은 작업이 남아있다면 뒤로 재삽입
                queue.offer(cur);
            }
        }
        return count;
    }
    
    // 인덱스 + 우선순위를 함께 보관할 DTO
    static class DTO {
        int idx;
        int priority;
        DTO(int idx, int priority) {
            this.idx = idx;
            this.priority = priority;
            // System.out.println("idx: "+idx+" priority: "+priority);
        }
    }
}

💡TIL

배운 점이 있다면 입력해주세요

  • 처음에 인덱스와 우선순위를 딕셔너리로 저장한 후, 이를 큐로 바꾸려고 파이썬했다. 하지만 파이썬이 아닌 자바에서는 이를 어떻게 해야 할 지 몰랐다. 파이썬처럼 처리하려다보니 에러가 많이 나게 되었고, 이 과정에서 DTO를 사용할 수 있다는 것을 알게 되었다.
  • Queue와 마찬가지로 우선순위 큐 (PriorityQueue) 클래스가 존재한다.
  • QueuePriorityQueue에서 사용되는 함수가 헷갈린다. 꼭 기억하자
    • push: offer()
    • pop: poll()
    • 가장 첫번째 값 가져오기: peek()

백준 #1283. 단축키 지정: 구현 / 실버1

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 입력으로 옵션 개수 N을 받는다.
  2. shortcut_key 집합을 만들어 단축키 등록 현황을 저장한다.
  3. 각 옵션(option) 문장을 공백 기준으로 나눈다.
    1. 1단계: 각 단어의 첫 글자를 확인해 등록 가능 여부 판단한다. 만약 있을 경우 [ ] 로 감싼 값을 return 한다.
    2. 2단계: 전체 문자를 왼쪽부터 순회하며 등록 가능한 단축키 탐색한다. 만약 있을 경우 [ ] 로 감싼 값을 return 한다.
    3. 위 1, 2단계 어느 조건에도 해당하지 않을 경우 원래 option을 그대로 return 한다.
  4. 반환된 값을 문자열로 출력한다.

🚩제출한 코드

import sys
input = sys.stdin.readline


def setOptions(option):
    # 1. 각 단어의 첫 글자 우선 확인
    for i in range(len(option)):
        if option[i][0].upper() not in shortcut_key:
            shortcut_key.add(option[i][0].upper())
            option[i] = f"[{option[i][0]}]{option[i][1:]}"
            return option
            
    # 2. 전체 단어의 모든 글자 중 아직 등록되지 않은 글자 탐색
    for i in range(len(option)):
        for j in range(len(option[i])):
            if option[i][j].upper() not in shortcut_key:
                shortcut_key.add(option[i][j].upper())
                option[i] = f"{option[i][:j]}[{option[i][j]}]{option[i][j+1:]}"
                return option
                
   # 3. 지정할 수 있는 단축키가 없는 경우
    return option


N = int(input())
shortcut_key = set()

for _ in range(N):
    option = input().split()
    result = setOptions(option)
    print(' '.join(result))

💡TIL

배운 점이 있다면 입력해주세요

  • **문제의 조건을 정확히 판단**해야 한다. 문제를 대충 읽고 접근하여 풀이 중반부가 되어서야 잘못된 방향으로 가고 있었다는 것을 알게 되었다.

백준 #2564. 경비원: 구현 / 실버1

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 전체 외곽 길이를 perimeter = 2 * (w + h)로 구한다.
  2. 모든 상점과 동근이의 위치를 (dir, dist) 형태로 입력받는다.
  3. to_pos() 함수를 통해 모두 1차원 좌표로 변환한다.
  4. 동근이 위치와 각 상점의 위치 차이를 구한다.
  5. 거리 차이는 min(정방향 거리, 역방향 거리)로 계산한다.
  6. 총 거리를 누적하여 출력한다.

🚩제출한 코드

import sys
input = sys.stdin.readline

# 1. 입력받기
w, h = map(int, input().split())    # 가로, 세로
store_cnt = int(input())            # 상점의 개수

# 2. 둘레 계산
perimeter = 2 * (w + h)

# 3. (방향, 거리) -> 1차원 위치로 변환 함수
def to_pos(dir, dist):
    if dir == 1:    # 북
        return dist
    if dir == 2:    # 남
        return w + h + (w - dist)
    if dir == 3:    # 서
        return 2*w + h + (h - dist)
    if dir == 4:    # 동
        return w + dist


# 4. 모든 상점의 위치를 1차원 조표로 변환해서 리스트에 모으기
store_loc = []  # 상점의 위치
for _ in range(store_cnt):
    d, dist = map(int, input().split())
    store_loc.append(to_pos(d, dist))

# 5. 경비원 위치도 똑같이 변환
gd, gdist = map(int, input().split())
guard_pos = to_pos(gd, gdist)

# print(f"store: {store_loc}")
# print(f"guard: {guard_pos}")

# 6. 각 상점까지 최단 거리 구해서 합산
total = 0
for store in store_loc:
    diff = abs(store - guard_pos)
    # 시계방향 <-> 반시계방향 중 짧은 거리 선택
    total += min(diff, perimeter - diff)

# 7. 결과 출력
print(total)

💡TIL

배운 점이 있다면 입력해주세요

  • 이 문제는 사각형 경계선을 1차원 좌표로 단순화하는 발상이 핵심이었다.
  • 처음에는 모든 방향 조합에 대한 조건 분기를 생각했으나 너무 복잡해서 결국 포기하게 되었다. 이 문제를 통해 새로운 접근법을 배우게 되었다. 1차원으로 단순화하면 abs 차이perimeter - 차이 중 최소값만 비교하면 된다.
  • 앞으로도 조건이 복잡한 문제는 **“다른 방식으로 표현할 수 없을까?”**를 먼저 고민해보자.

프로그래머스 #12906. 같은숫자는싫어: 스택큐 / Level1

정리한 링크: (바로가기)

🚩플로우 (선택)

코드를 풀이할 때 적었던 플로우가 있나요?

  1. 배열 arr에서 첫 값을 answer 리스트에 추가한다.
  2. 두 번째 요소부터 마지막까지 순회하면서:
    • 바로 이전 값과 다르면 answer에 추가한다.
  3. 리스트를 정답 배열로 변환한 후 리턴한다.

🚩제출한 코드

import java.util.*;

public class Solution {
    public int[] solution(int []arr) {
        ArrayList<Integer> answer = new ArrayList<>();
        
        // 1. 첫 번째 값은 무조건 추가
        answer.add(arr[0]);
        
        // 2. 두 번째 값부터 순차적으로 확인
        for (int i = 1; i < arr.length; i++) {
		        // 바로 이전 값과 다르면 추가
            if (answer.get(answer.size()-1) != arr[i]) {
                answer.add(arr[i]);
            }
        }
        
        // 3. ArrayList → int[] 변환
        int[] answer2 = new int[answer.size()];
        for (int i = 0; i < answer.size(); i++){
            answer2[i] = answer.get(i);
        }
        return answer2;
    }
}

💡TIL

배운 점이 있다면 입력해주세요

  • ArrayListArray로 변환할 때 자꾸만 헷갈려서 문제 풀이에 어려움을 겪는다. 앞으로는 아래 내용은 아예 외워두어야겠다.

    int[] answer = new int[tempList.size()];
    for(int i=0; i<answer.length; i++) {
        answer[i] = tempList.get(i).intValue();
    }
    • 배열 선언 시 앞에 type을 꼭 써줘야 한다.
    • ArrayList 조회할 때는 get 함수를 써야 한다.
  • 스택/큐 섹션에 있던 문제였는데 왜 스택인지 이해를 못했다. 하지만 다른 분의 풀이를 보며 Stack 클래스를 이용해서 충분히 풀 수 잇다는 것을 알게 되었다.

Comment on lines +29 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 문제는 시간복잡도가 넉넉해서 상관없긴 하지만,
이 문제는 민정님처럼 for문안에서 입력받기, 단축키 지정 두 가지를 한번에 하는 로직이 더 좋겠네요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 문제에서는 직사각형 블록 외각에만 길이 있기 때문에, 시계 방향과 반시계 방향 두 가지 길만 존재하는 점을 이용하여 두 방향 중 하나를 구하고 블록의 둘레의 50%와 비교하여 정답을 정하는게 핵심이었던 문제 같습니다. 상점과 동근이의 거리를 구할 때, (0,0)을 기준점으로 잡고 블록의 width, height, dist(상점이 기준점에서 떨어진 거리)를 조합하여 푸는 이 부분이 문제의 핵심인 것 같아요.

Copy link
Member

@YoonYn9915 YoonYn9915 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

한 주 수고하셨습니다!

@Mingguriguri Mingguriguri merged commit d0deb81 into main May 18, 2025
@github-actions
Copy link

🔥2025-05 챌린지 진행 상황

👉 그래프

  • YoonYn9915: 0개 ❌
  • Mingguriguri: 2개 ❌
  • zaqquum: 1개 ❌

👉 구현

  • YoonYn9915: 0개 ❌
  • Mingguriguri: 0개 ❌
  • zaqquum: 0개 ❌

@github-actions
Copy link

🔥2025-05 챌린지 진행 상황

👉 그래프

  • YoonYn9915: 0개 ❌

👉 구현

  • YoonYn9915: 2개 ❌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants